﻿using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;

namespace Services
{
    public class CameraConsumer : Microsoft.Xna.Framework.DrawableGameComponent
    {
        protected Vector3 EyePosition { get { return Vector3.Transform(-view.Translation, Matrix.Transpose(view)); } }
        protected Microsoft.Xna.Framework.Matrix view;
        protected Microsoft.Xna.Framework.Matrix projection;
        protected float max_depth;
        protected CameraProvider provider;
        public void SetCamera(Microsoft.Xna.Framework.Matrix view, Microsoft.Xna.Framework.Matrix projection, float max_depth)
        {
            this.view = view;
            this.projection = projection;
            this.max_depth = max_depth;
        }

        public CameraConsumer(Game game) : base(game) { }
        public override void Initialize()
        {
            var camera_provider = Game.Services.GetService(typeof(CameraProvider)) as CameraProvider;
            camera_provider.AddCameraConsumer(this);
            this.provider = camera_provider;
            base.Initialize();
        }

    }

    public class CameraProvider : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public enum FIELDOFVIEW { PROSPECTIVE, ORTHOGONAL};
        FIELDOFVIEW field;

        public CameraProvider(Game game, FIELDOFVIEW field)
            : base(game)
        {
            game.Services.AddService(typeof(CameraProvider), this);
            this.field = field;
            UpdateOrder = 0;
        }

        /// Alla chiusura facciamo pulizia dei servizi istanziati
        protected override void Dispose(bool disposing)
        {
            Game.Services.RemoveService(typeof(CameraProvider));
            base.Dispose(disposing);
        }

        public Vector3 EyePosition { get { return Vector3.Transform(-view.Translation, Matrix.Transpose(view)); } }
        public Matrix view = Matrix.CreateLookAt(new Vector3(400, 240, -(float)(240 / Math.Sin(MathHelper.PiOver4) * Math.Cos(MathHelper.PiOver4))), new Vector3(400, 240, 0), Vector3.Down);
        public Matrix projection;
        public float max_depth = 200.0f;

        protected override void LoadContent()
        {
            if (field == FIELDOFVIEW.PROSPECTIVE)
            {
                projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height, 0.1f, 1000f);
                    //Matrix.CreatePerspectiveFieldOfView(1.5f * GraphicsDevice.Viewport.Width / 800.0f,
                    //GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height, 0.1f, max_depth);
            }
            else
            {
                projection = Matrix.CreateOrthographicOffCenter(0,800,480,0,0,100);
            }

            base.LoadContent();
        }

        List<CameraConsumer> camera_consumers = new List<CameraConsumer>(20);
        public void AddCameraConsumer(CameraConsumer consumer)
        {
            camera_consumers.Add(consumer);
        }

        public void RemoveCameraConsumer(CameraConsumer consumer)
        {
            camera_consumers.Remove(consumer);
        }

        public override void Update(GameTime gameTime)
        {
            for (int i = 0; i < camera_consumers.Count; i++)
                camera_consumers[i].SetCamera(view, projection, max_depth);

            base.Update(gameTime);
        }
    }
}
